修改這一堂的範例,計算「每個人」、「每個分工項目」統計排班的次數,並加上排名
SELECT  CleanSchedule_CountResult.FamilyName,
        CleanSchedule_CountResult.ItemName,
        CleanSchedule_CountResult.Count_Number,
        RANK() OVER (ORDER BY CleanSchedule_CountResult.Count_Number DESC) AS CountNumber
FROM ( 
       SELECT DISTINCT
              Family.FamilyName,
              CleanItemList.ItemName,
              COUNT(CleanSchedule.CleanItem) OVER (PARTITION BY Family.FamilyName, CleanItemList.ItemName) AS Count_Number
       FROM family
       INNER JOIN CleanItemList
       ON 1 = 1
       LEFT JOIN CleanSchedule
       ON 	Family.FamilyID = CleanSchedule.FamilyId AND
            CleanItemList.CleanItem = CleanSchedule.CleanItem
     ) AS CleanSchedule_CountResult
| FamilyName | ItemName | Count_Number | Rank | 
|---|---|---|---|
| 泰賢 | 打掃 | 4 | 1 | 
| 泰熱 | 拖地 | 4 | 1 | 
| 泰肝 | 洗碗 | 4 | 1 | 
| 泰賢 | 拖地 | 3 | 4 | 
| 泰瘦 | 倒垃圾 | 3 | 4 | 
| 泰肝 | 倒垃圾 | 3 | 4 | 
| 泰冷 | 拖地 | 3 | 4 | 
| 泰瘦 | 洗碗 | 3 | 4 | 
| 泰胖 | 洗碗 | 3 | 4 | 
| 泰熱 | 打掃 | 3 | 4 | 
| 泰熱 | 倒垃圾 | 2 | 1 | 
| 泰熱 | 倒垃圾 | 2 | 11 | 
| 泰胖 | 打掃 | 2 | 11 | 
| 泰胖 | 倒垃圾 | 2 | 11 | 
| 泰冷 | 打掃 | 2 | 11 | 
| 泰賢 | 洗碗 | 2 | 11 | 
| 泰冷 | 倒垃圾 | 2 | 11 | 
| 泰肝 | 打掃 | 1 | 17 | 
| 泰熱 | 洗碗 | 1 | 17 | 
| 泰賢 | 倒垃圾 | 1 | 17 | 
| 泰瘦 | 拖地 | 1 | 17 | 
| 泰肝 | 拖地 | 1 | 17 | 
| 泰瘦 | 打掃 | 1 | 17 | 
| 泰胖 | 拖地 | 1 | 17 | 
| 泰冷 | 洗碗 | 0 | 24 | 
1. 產生每個人、每個工作項目的清單
將每個人跟每個打掃項目,透過JOIN ON 1 = 1 的關聯方式產生
SELECT *
FROM Family
INNER JOIN CleanItemList
ON 1 = 1
| FamilyName | ItemName | 
|---|---|
| 泰肝 | 打掃 | 
| 泰肝 | 拖地 | 
| 泰肝 | 洗碗 | 
| 泰肝 | 倒垃圾 | 
| 泰熱 | 打掃 | 
| 泰熱 | 拖地 | 
| 泰熱 | 洗碗 | 
| 泰熱 | 倒垃圾 | 
| 泰胖 | 打掃 | 
| 泰胖 | 拖地 | 
| 泰胖 | 洗碗 | 
| 泰胖 | 倒垃圾 | 
| 泰瘦 | 打掃 | 
| 泰瘦 | 拖地 | 
| 泰瘦 | 洗碗 | 
| 泰瘦 | 倒垃圾 | 
| 泰冷 | 打掃 | 
| 泰冷 | 拖地 | 
| 泰冷 | 洗碗 | 
| 泰冷 | 倒垃圾 | 
| 泰賢 | 打掃 | 
| 泰賢 | 拖地 | 
| 泰賢 | 洗碗 | 
| 泰賢 | 倒垃圾 | 
2. 使用Count函數計算每個人的分工次數
在Count函數後方,透過OVER子句的PARTITION BY,先將資料依照「成員ID」、「負責項目」進行分類,計算每個人在每個分工的排班次數分配
SELECT DISTINCT
       Family.FamilyName,
       CleanItemList.ItemName,
       COUNT(CleanSchedule.CleanItem) OVER (PARTITION BY Family.FamilyId, CleanItemList.ItemName) AS Count_Number
FROM family
INNER JOIN CleanItemList
ON 1 = 1
LEFT JOIN CleanSchedule
ON 	Family.FamilyID = CleanSchedule.FamilyId AND
    CleanItemList.CleanItem = CleanSchedule.CleanItem
| FamilyName | ItemName | Count_Number | 
|---|---|---|
| 泰肝 | 倒垃圾 | 3 | 
| 泰肝 | 打掃 | 1 | 
| 泰肝 | 拖地 | 1 | 
| 泰肝 | 洗碗 | 4 | 
| 泰熱 | 倒垃圾 | 2 | 
| 泰熱 | 打掃 | 3 | 
| 泰熱 | 拖地 | 4 | 
| 泰熱 | 洗碗 | 1 | 
| 泰胖 | 倒垃圾 | 2 | 
| 泰胖 | 打掃 | 2 | 
| 泰胖 | 拖地 | 1 | 
| 泰胖 | 洗碗 | 3 | 
| 泰瘦 | 倒垃圾 | 3 | 
| 泰瘦 | 打掃 | 1 | 
| 泰瘦 | 拖地 | 1 | 
| 泰瘦 | 洗碗 | 3 | 
| 泰冷 | 倒垃圾 | 2 | 
| 泰冷 | 打掃 | 2 | 
| 泰冷 | 拖地 | 3 | 
| 泰冷 | 洗碗 | 0 | 
| 泰賢 | 倒垃圾 | 1 | 
| 泰賢 | 打掃 | 4 | 
| 泰賢 | 拖地 | 3 | 
| 泰賢 | 洗碗 | 2 | 
3.將子查詢統計出來的排班次數,透過Rank 函數進行排名的處理
在Rank 函數後方,透過OVER子句的ORDER BY,將資料依照排班次數多到排班次數少的進行排序後,給予1、2、3等等排名
SELECT  CleanSchedule_CountResult.FamilyName,
        CleanSchedule_CountResult.ItemName,
        CleanSchedule_CountResult.Count_Number,
        RANK() OVER (ORDER BY CleanSchedule_CountResult.Count_Number DESC) AS CountNumber
FROM ( 
       SELECT DISTINCT
              Family.FamilyName,
              CleanItemList.ItemName,
              COUNT(CleanSchedule.CleanItem) OVER (PARTITION BY Family.FamilyId, CleanItemList.ItemName) AS Count_Number
       FROM family
       INNER JOIN CleanItemList
       ON 1 = 1
       LEFT JOIN CleanSchedule
       ON   Family.FamilyID = CleanSchedule.FamilyId AND
				  CleanItemList.CleanItem = CleanSchedule.CleanItem
     ) AS CleanSchedule_CountResult
| FamilyName | ItemName | Count_Number | Rank | 
|---|---|---|---|
| 泰賢 | 打掃 | 4 | 1 | 
| 泰熱 | 拖地 | 4 | 1 | 
| 泰肝 | 洗碗 | 4 | 1 | 
| 泰賢 | 拖地 | 3 | 4 | 
| 泰瘦 | 倒垃圾 | 3 | 4 | 
| 泰肝 | 倒垃圾 | 3 | 4 | 
| 泰冷 | 拖地 | 3 | 4 | 
| 泰瘦 | 洗碗 | 3 | 4 | 
| 泰胖 | 洗碗 | 3 | 4 | 
| 泰熱 | 打掃 | 3 | 4 | 
| 泰熱 | 倒垃圾 | 2 | 1 | 
| 泰熱 | 倒垃圾 | 2 | 11 | 
| 泰胖 | 打掃 | 2 | 11 | 
| 泰胖 | 倒垃圾 | 2 | 11 | 
| 泰冷 | 打掃 | 2 | 11 | 
| 泰賢 | 洗碗 | 2 | 11 | 
| 泰冷 | 倒垃圾 | 2 | 11 | 
| 泰肝 | 打掃 | 1 | 17 | 
| 泰熱 | 洗碗 | 1 | 17 | 
| 泰賢 | 倒垃圾 | 1 | 17 | 
| 泰瘦 | 拖地 | 1 | 17 | 
| 泰肝 | 拖地 | 1 | 17 | 
| 泰瘦 | 打掃 | 1 | 17 | 
| 泰胖 | 拖地 | 1 | 17 | 
| 泰冷 | 洗碗 | 0 | 24 | 
藉由上方的結果可以發現
因為有三個相同的排班次數4排在前面,所以3個會並列第1名
排班次數第二高的3的名次會遞延到「第4名」開始
如果希望名次不要遞延,可以使用DENSE_RANK()函數
| FamilyName | ItemName | Count_Number | Rank | 
|---|---|---|---|
| 泰熱 | 拖地 | 4 | 1 | 
| 泰肝 | 洗碗 | 4 | 1 | 
| 泰賢 | 打掃 | 4 | 1 | 
| 泰胖 | 洗碗 | 3 | 2 | 
| 泰瘦 | 洗碗 | 3 | 2 | 
| 泰熱 | 打掃 | 3 | 2 | 
| 泰肝 | 倒垃圾 | 3 | 2 | 
| 泰冷 | 拖地 | 3 | 2 | 
| 泰賢 | 拖地 | 3 | 2 | 
| 泰瘦 | 倒垃圾 | 3 | 2 | 
| 泰賢 | 洗碗 | 2 | 3 | 
| 泰胖 | 打掃 | 2 | 3 | 
| 泰熱 | 倒垃圾 | 2 | 3 | 
| 泰胖 | 倒垃圾 | 2 | 3 | 
| 泰冷 | 打掃 | 2 | 3 | 
| 泰冷 | 倒垃圾 | 2 | 3 | 
| 泰賢 | 倒垃圾 | 1 | 4 | 
| 泰肝 | 打掃 | 1 | 4 | 
| 泰胖 | 拖地 | 1 | 4 | 
| 泰瘦 | 拖地 | 1 | 4 | 
| 泰瘦 | 打掃 | 1 | 4 | 
| 泰熱 | 洗碗 | 1 | 4 | 
| 泰肝 | 拖地 | 1 | 4 | 
| 泰冷 | 洗碗 | 0 | 5 | 
https://www.w3schools.com/sql/trymysql.asp?filename=trysql_func_mysql_cast
找出所有國家位於「德國(Germany)」的供應商與客戶
SELECT 'Customer' As Type, ContactName, City, Country
FROM Customers
WHERE Country = 'Germany'
UNION
SELECT 'Supplier' As Type, ContactName, City, Country
FROM Suppliers
WHERE Country = 'Germany'
| Type | ContactName | City | Country | 
|---|---|---|---|
| Customer | Alexander Feuer | Leipzig | Germany | 
| Customer | Hanna Moos | Mannheim | Germany | 
| Customer | Henriette Pfalzheim | K闤n | Germany | 
| Customer | Horst Kloss | Cunewalde | Germany | 
| Customer | Karin Josephs | M?ster | Germany | 
| Customer | Maria Anders | Berlin | Germany | 
| Customer | Peter Franken | M?chen | Germany | 
| Customer | Philip Cramer | Brandenburg | Germany | 
| Customer | Renate Messner | Frankfurt a.M. | Germany | 
| Customer | Rita M悤ler | Stuttgart | Germany | 
| Customer | Sven Ottlieb | Aachen | Germany | 
| Supplier | Martin Bein | Frankfurt | Germany | 
| Supplier | Petra Winkler | Berlin | Germany | 
| Supplier | Sven Petersen | Cuxhaven | Germany | 
以範例的「供應商」和「客戶」為例
這兩張資料表的欄位除了「CustomerID」、「SupplierID」、「CustomerName」和「Supplier」不一樣之外
都有「ContactName」、「Address」、「City」、「PostalCode」、「Country」這五個欄位
像這樣子的情境,來自不同資料來源,但結構相同的查詢
可以使用UNION 查詢
1.UNION:資料來源A的查詢結果 合併 資料來源B的查詢結果,過濾掉兩邊重複的結果
SELECT 資料來源A.欄位1, 資料來源A.欄位2, 資料來源A.欄位3 ... 資料來源A.欄位N
FROM 資料來源A
UNION
SELECT 資料來源B.欄位1, 資料來源B.欄位2, 資料來源B.欄位3 ... 資料來源B.欄位N
FROM 資料來源B
2.UNION ALL:資料來源A的查詢結果 合併 資料來源B的查詢結果,不要過濾掉兩邊重複的結果
SELECT 資料來源A.欄位1, 資料來源A.欄位2, 資料來源A.欄位3 ... 資料來源A.欄位N
FROM 資料來源A
UNION ALL
SELECT 資料來源B.欄位1, 資料來源B.欄位2, 資料來源B.欄位3 ... 資料來源B.欄位N
FROM 資料來源B
錯誤範例:
SELECT 'Customer' As Type, ContactName
FROM Customers
WHERE Country = 'Germany'
UNION
SELECT 'Supplier' As Type, ContactName, City, Country
FROM Suppliers
WHERE Country = 'Germany'

錯誤原因:
兩邊查詢欄位數量不一致
Customers的SELECT查詢有「Type」跟「ContactName」2個欄位
Suppliers的SELECT查詢有「Type」、「ContactName」、「City」「 Country」4個欄位
SELECT BirthDate
FROM Employees
UNION
SELECT SupplierName
FROM Suppliers
在網址或自己的資料庫系統測試後
會發現BirthDate是DateTime,SupplierName是Varchar
卻可以UNION,是因為DBMS幫我們把兩者全部轉換成Varchar做聯集
正確範例:
SELECT 'Customer' As Type, ContactName, City, Country
FROM Customers
WHERE Country = 'Germany'
UNION
SELECT 'Supplier' As Type, ContactName, City, Country
FROM Suppliers
WHERE Country = 'Germany'
ORDER BY ContactName
錯誤範例:
SELECT 'Customer' As Type, ContactName, City, Country
FROM Customers
WHERE Country = 'Germany'
ORDER BY ContactName
UNION
SELECT 'Supplier' As Type, ContactName, City, Country
FROM Suppliers
WHERE Country = 'Germany'
ORDER BY ContactName

錯誤原因:
Order By 出現在UNION 聯集查詢的兩邊。
例如:幫我查詢國家位於「德國」的客戶與供應商的「城市」和「家鄉」
由於位於德國的客戶和應商,都有City = Berlin 和 Country = Germany

如果希望聯集完後不要有重複的資料,在UNION後方不要加上ALL。
SELECT 區塊除了顯示來自所有查詢來源的資料
還可以自行給予一個字串,定義一個額外的欄位
以這堂的課堂的範例為例:
Customer的聯集查詢,自行定義一個Type欄位,內容是Customer
Suppliers的聯集查詢,自行定義一個Type欄位,內容是Supplier
https://www.w3resource.com/sql-exercises/union/sql-union-exercise-4.php
請根據「業務」與「訂單」兩張資料表,統計每一天業績最高與業績最低的業務,與業務訂單量
需列出的欄位
| ord_date | name | category | count | 
|---|---|---|---|
| 2012-04-25 | James Hoog | HIGHEST | 3045.60 | 
| 2012-04-25 | James Hoog | LOWEST | 3045.60 | 
| 2012-06-27 | Nail Knite | HIGHEST | 250.45 | 
| 2012-06-27 | Nail Knite | LOWEST | 250.45 | 
| 2012-07-27 | James Hoog | HIGHEST | 2400.60 | 
| 2012-07-27 | James Hoog | LOWEST | 2400.60 | 
| 2012-08-17 | Lauson Hen | HIGHEST | 110.50 | 
| 2012-08-17 | Paul Adam | LOWEST | 75.29 | 
| 2012-09-10 | James Hoog | HIGHEST | 5760.00 | 
| 2012-09-10 | Pit Alex | LOWEST | 270.65 | 
| 2012-10-05 | Nail Knite | HIGHEST | 150.50 | 
| 2012-10-05 | James Hoog | LOWEST | 65.26 | 
| 2012-10-10 | Lauson Hen | HIGHEST | 2480.40 | 
| 2012-10-10 | Mc Lyon | LOWEST | 1983.43 | 

1.這題是原本題目的變化題,答案與原題目不同
2.在此網站,UNION後方的查詢請使用()包起來,例如:
SELECT XXX
FROM A
UNION (
SELECT XXX
FROM B
)